import { MockOptions, MockContext } from './type'
import { IncomingMessage, ServerResponse } from 'http'
import { ViteDevServer } from 'vite'
import url from 'url'
import path from 'path'
import fs from 'fs'

const log = {
  debug: (...args: any[]) => console.debug('[Mock]', ...args),
  error: (...args: any[]) => console.error('[Mock]', ...args),
  info: (...args: any[]) => console.info('[Mock]', ...args),
}

/**
 * 根据配置决定是否mock
 * @param req 请求
 * @param options 配置
 * @returns 是否需要mock
 */
export function shouldMock(req: IncomingMessage, options: Required<MockOptions>): boolean {
  const mock = req.headers.mock
  if (!mock) return false
  if (process.env.NODE_ENV === 'production') return false
  return options.requestMatch(req)
}

export function createMockContext(
  req: IncomingMessage,
  res: ServerResponse,
  options: Required<MockOptions>
): MockContext {
  const mockPath = req.headers.mockpath as string
  const cleanPath = mockPath || cleanRequestPath(req)

  return {
    req,
    res,
    options,
    cleanPath,
  }
}

/**
 * 解析读取mock文件的路径
 * 如果没有mockPath配置项，则通过该函数解析url参数，获取读取mock的文件路径
 * /a/b/c?p1=1&p2=2 => c
 * @param req 请求
 * @returns 解析后的路径
 */
function cleanRequestPath(req: IncomingMessage): string {
  const parsedUrl = url.parse(req.url || '', true)
  const parts = parsedUrl.pathname?.split('/').filter(Boolean)
  if (parts) {
    return parts[parts.length - 1]
  } else {
    return ''
  }
}

/**
 * 加载mock数据
 * @param context 上下文
 * @param server Vite服务器
 * @returns 加载的mock数据
 */
export async function loadMockData(context: MockContext, server: ViteDevServer) {
  const { cleanPath, options } = context
  const mockRoot = path.resolve(process.cwd(), options.root)

  const jsPath = path.resolve(mockRoot, `${cleanPath}.js`)
  const jsonPath = path.resolve(mockRoot, `${cleanPath}.json`)

  if (options.debug) {
    log.debug('Looking for mock files:', {
      js: jsPath,
      json: jsonPath,
    })
  }

  try {
    // 优先加载 JS 文件
    if (fs.existsSync(jsPath)) {
      return await loadJsMock(jsPath, context, server)
    }

    // 然后尝试加载 JSON 文件
    if (fs.existsSync(jsonPath)) {
      return await loadJsonMock(jsonPath)
    }

    throw new Error(`Mock file not found: ${cleanPath}`)
  } catch (error) {
    if (options.debug) {
      log.error('Failed to load mock data:', error)
    }
    throw error
  }
}

/**
 * 加载JS mock数据
 * @param jsPath JS文件路径
 * @param context 上下文
 * @param server Vite服务器
 * @returns 加载的mock数据
 */
async function loadJsMock(jsPath: string, context: MockContext, server: ViteDevServer) {
  const modulePath = `/@fs/${jsPath}`
  const module = await server.ssrLoadModule(modulePath)
  // 解析请求体数据
  const params = await requestParams(context)
  if (typeof module.default === 'function') {
    // 将解析后的请求参数传递给 mock 处理函数
    return await module.default({
      ...context.req,
      params, // 添加解析后的请求数据
    })
  }
  return module.default
}

/**
 * 解析请求参数
 * @param context 上下文
 * @returns 解析后的请求参数
 */
async function requestParams(context: MockContext) {
  // 解析请求体数据
  let requestData = {}

  if (context.req.method === 'POST') {
    // 处理 POST 请求体
    const buffers: any[] = []
    for await (const chunk of context.req) {
      buffers.push(chunk)
    }
    const data = Buffer.concat(buffers).toString()
    try {
      requestData = convertValues(JSON.parse(data))
    } catch (e) {
      // 解析失败时保持空对象
    }
  } else if (context.req.method === 'GET') {
    // 处理 GET 查询参数
    const parsedUrl = url.parse(context.req.url || '', true)
    requestData = convertValues(parsedUrl.query)
  }
  return requestData
}

/**
 * 加载JSON mock数据
 * @param jsonPath JSON文件路径
 * @returns JSON数据
 */
async function loadJsonMock(jsonPath: string) {
  const content = await fs.promises.readFile(jsonPath, 'utf-8')
  return JSON.parse(content)
}

/**
 * 发送响应
 * @param context 上下文
 * @param data 响应数据
 */
export async function sendResponse(context: MockContext, data: any) {
  const { req, res, options } = context
  const delay = Number(req.headers.mockdelay) || options.delay

  await new Promise(resolve => setTimeout(resolve, delay))

  res.setHeader('Content-Type', 'application/json')
  res.setHeader('X-Powered-By', 'vite-plugin-mock')
  res.end(JSON.stringify(data))
}

export function handleError(error: any, res: ServerResponse, options: Required<MockOptions>) {
  if (options.debug) {
    log.error('Mock middleware error:', error)
  }

  res.statusCode = error.statusCode || 500
  res.setHeader('Content-Type', 'application/json')

  const errorResponse = {
    error: true,
    message: options.debug ? error.message : 'Internal mock server error',
    stack: options.debug ? error.stack : undefined,
  }

  res.end(JSON.stringify(errorResponse))
}

/**
 *  递归处理对象中的所有值,将基本类型的值转为实际类型，
 * 比如'123'转为123,
 * 'true'转为true,
 * 'false'转为false,
 * 'null'转为null,
 * 'undefined'转为undefined,
 * 其他情况保持字符串
 * @param obj
 * @returns
 */
function convertValues(obj: Record<string, any>): Record<string, any> {
  const result: Record<string, any> = {}

  for (const key in obj) {
    const value = obj[key]
    if (Array.isArray(value)) {
      result[key] = value.map(item =>
        typeof item === 'object' ? convertValues(item) : convertValue(item)
      )
    } else if (typeof value === 'object' && value !== null) {
      result[key] = convertValues(value)
    } else if (typeof value === 'string') {
      result[key] = convertValue(value)
    } else {
      result[key] = value
    }
  }

  return result
}

// 添加一个类型转换的工具函数
function convertValue(value: string) {
  // 处理数字
  // 处理数字
  if (/^-?\d+$/.test(value)) {
    // 添加可选的负号 -?
    return parseInt(value, 10)
  }
  if (/^-?\d*\.?\d+$/.test(value)) {
    // 添加可选的负号 -?
    return parseFloat(value)
  }
  // 处理布尔值
  if (value === 'true') return true
  if (value === 'false') return false
  // 处理 null
  if (value === 'null') return null
  if (value === 'undefined') return undefined
  // 其他情况保持字符串
  return value
}
